Terrain intersection
Description
-
This is a custom interactive tool for terrain and smart line intersection.
-
The user is prompted for line selection which user needs to select from UI from 3D view.
-
After line selection, this tool uses active terrain surface to find the intersection between terrain and line.
-
The TerrainIntersection class which extends DgnElementSetTool which handles different events to interact with UI, the TerrainIntersection class overrides the events here in this tool.
-
The method OnDataButton() handles the line selection from 3D view.
Remarks
-
This sample code is a part of ManagedSDKExample which you get with SDK installation under "examples" section in SDK installation directory.
-
If you encounter any error while using DgnElementSetTool class, make sure to add a reference to Bentley.DgnDisplayNet.dll by selecting Project > Add Reference or change the projects.csproj file to add reference to this dll .
-
The default dll location will be "C:\Program Files\Bentley\OpenRoads Designer CE 10.11\OpenRoadsDesigner\Bentley.DgnDisplayNet.dll".
Source Code
using System.Collections.Generic;
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.CifNET.GeometryModel.SDK;
using Bentley.CifNET.SDK;
using Bentley.CifNET.LinearGeometry;
namespace ManagedSDKExample
{
class TerrainIntersection : DgnElementSetTool
{
ConsensusConnection m_con;
public TerrainIntersection() : base()
{
}
protected override void OnRestartTool()
{
InstallNewInstance();
}
protected override void ExitTool()
{
if (m_con != null)
{
m_con.Close();
m_con.Dispose();
}
m_con = null;
base.ExitTool();
}
protected override void OnPostInstall()
{
base.BeginPickElements();
m_con = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive();
if (m_con == null)
return;
base.OnPostInstall();
NotificationManager.OutputPrompt("Select SmartLine from 3D view");
}
//Select line from 3D view
protected override bool OnDataButton(Bentley.DgnPlatformNET.DgnButtonEvent ev)
{
Bentley.DgnPlatformNET.HitPath hitPath = DoLocate(ev, true, 1);
if (hitPath == null)
return false;
Element el = hitPath.GetCursorElement();
if (el == null)
return false;
if (el.ElementType == MSElementType.LineString)
TerrainAndLineIntersection(el);
else
return false;
return true;
}
public override Bentley.DgnPlatformNET.StatusInt OnElementModify(Bentley.DgnPlatformNET.Elements.Element element)
{
return Bentley.DgnPlatformNET.StatusInt.Error;
}
protected override bool OnResetButton(Bentley.DgnPlatformNET.DgnButtonEvent ev)
{
ExitTool();
return true;
}
public static void InstallNewInstance()
{
TerrainIntersection tool = new TerrainIntersection();
tool.InstallTool();
}
public bool IntersectVector(Bentley.TerrainModelNET.DTM dtm, out Bentley.GeometryNET.DSegment3d intersectionSegment, Bentley.GeometryNET.DPoint3d startPt, Bentley.GeometryNET.DPoint3d endPt)
{
intersectionSegment = new Bentley.GeometryNET.DSegment3d();
//Project the start and end points of line to terrain surface
var drapeResult = dtm.DrapeLinearPoints(new Bentley.GeometryNET.DPoint3d[] { startPt, endPt });
double vectorDist = startPt.DistanceXY(endPt);
double vectorZDiff = endPt.Z - startPt.Z;
bool hasPrevPt = false;
Bentley.GeometryNET.DPoint3d prevPt = new Bentley.GeometryNET.DPoint3d();
double prevZ = 0;
bool prevAbove = false;
foreach (var drapePt in drapeResult)
{
//Check Drapped point position i.e., inside terrain or outside terrain boundry
if (drapePt.Code == Bentley.TerrainModelNET.DTMDrapedLinearElementPointCode.External || drapePt.Code == Bentley.TerrainModelNET.DTMDrapedLinearElementPointCode.Void)
{
hasPrevPt = false;
continue;
}
Bentley.GeometryNET.DPoint3d newPt = drapePt.Coordinates;
double newZ = startPt.Z + (drapePt.DistanceAlong / vectorDist) * vectorZDiff;
bool newAbove = newZ > newPt.Z;
if (hasPrevPt)
{
if (newAbove != prevAbove)
{
//Create line segment from start point and end point of line
Bentley.GeometryNET.DSegment3d seg1 = new Bentley.GeometryNET.DSegment3d(startPt, endPt);
//Create line from drapped points from start point and end point on terrain
Bentley.GeometryNET.DSegment3d seg2 = new Bentley.GeometryNET.DSegment3d(prevPt, newPt);
double f1, f2;
//intersect both line segment and terrain segment
Bentley.GeometryNET.DSegment3d.ClosestApproachSegment(seg1, seg2, out intersectionSegment, out f1, out f2);
//Get intersection point from intersection line
Bentley.GeometryNET.DPoint3d intersectPt = intersectionSegment.StartPoint;
return true;
}
}
hasPrevPt = true;
prevPt = drapePt.Coordinates;
prevZ = newZ;
prevAbove = newAbove;
}
return false;
}
public void TerrainAndLineIntersection(Element el)
{
//Get active connection of dgn model
ConsensusConnection sdkCon = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive();
if (sdkCon == null)
return;
//Get geometric model
GeometricModel geomModel = sdkCon.GetActiveGeometricModel();
if (geomModel == null)
return;
SurfaceEntity activeSurface = geomModel.ActiveSurface;
//Validate terrain surface and selected element
if (activeSurface != null && activeSurface is TerrainSurface && el.ElementType == MSElementType.LineString)
{
TerrainSurface surface = activeSurface as TerrainSurface;
List<LinearElement> segments = new List<LinearElement>();
//Get active Dgn model
DgnModel activeModel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
//Get model info to get units
ModelInfo info = activeModel.GetModelInfo();
//Convert Element to LineString
Bentley.DgnPlatformNET.Elements.LineStringElement lineString = el as Bentley.DgnPlatformNET.Elements.LineStringElement;
List<Bentley.GeometryNET.DPoint3d> pointList = new List<Bentley.GeometryNET.DPoint3d>();
Bentley.GeometryNET.CurvePrimitive curvePrim = lineString.GetCurveVector().GetPrimitive(0);
curvePrim.TryGetLineString(pointList);
//Get LineString points
for (int i = 0; i < pointList.Count - 1; i++)
{
Bentley.GeometryNET.DPoint3d point1 = pointList[i];
Bentley.GeometryNET.DPoint3d point2 = pointList[i + 1];
//Convert units to meter
point1.Set(point1.X / info.UorPerMeter, point1.Y / info.UorPerMeter, point1.Z / info.UorPerMeter);
point2.Set(point2.X / info.UorPerMeter, point2.Y / info.UorPerMeter, point2.Z / info.UorPerMeter);
//Create linear elements after converting units
segments.Add(new Line3d(point1, point2));
}
//For each linear element find intersection of it with terrain
foreach (LinearElement le in segments)
{
//Get intersecting line here
Bentley.GeometryNET.DSegment3d intersectLine = new Bentley.GeometryNET.DSegment3d();
bool intersects = IntersectVector(surface.DTM, out intersectLine, le.StartPoint.Coordinates, le.EndPoint.Coordinates);
}
}
}
}
}